using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Storage;
using System.Diagnostics;

namespace UWBGL_XNA_Lib13
{
    public class RGraphicsDeviceService : IGraphicsDeviceService
    {
        private GraphicsDevice m_graphicsDevice;

        public event EventHandler DeviceCreated;
        public event EventHandler DeviceDisposing;
        public event EventHandler DeviceReset;
        public event EventHandler DeviceResetting;

        public GraphicsDevice GraphicsDevice
        {
            get { return this.m_graphicsDevice; }
            set { m_graphicsDevice = value; }
        }
    }

    public class RGameView : IServiceProvider
    {
        public RGraphicsDeviceService m_graphicsDeviceService;

        public void SetService(RGraphicsDeviceService s)
        {
            m_graphicsDeviceService = s;
        }

        public object GetService(System.Type serviceType)
        {
            return this.m_graphicsDeviceService;
        }
    }
    //This is our custome vertex structure XNA likes to recieve 
    //arrays of structs with vertex information. For simple, unlit
    //drawing; a vertex and color at the vertex will suffice.
    public struct DeviceVertexFormat
    {
        private Vector3 m_Position;
        private Color m_Color;
        private Vector2 m_UV;

        //Format in which this type of vertex will be passed to the graphics hardware
        public static VertexElement[] VertexElements =
        {
            new VertexElement(0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, 
                              VertexElementUsage.Position, 0),
            new VertexElement(0, sizeof(float)*3, VertexElementFormat.Color, VertexElementMethod.Default, 
                              VertexElementUsage.Color, 0), 
            new VertexElement(0, (sizeof(float)*3)+sizeof(uint), VertexElementFormat.Vector2, VertexElementMethod.Default,
                              VertexElementUsage.TextureCoordinate, 0)
        };

        //m_Position accessor and modifier
        public Vector3 Position
        {
            get
            {
                return m_Position;
            }
            set
            {
                m_Position = value;
            }
        }

        //m_Color accessor and modifier
        public Color Color
        {
            get
            {
                return m_Color;
            }
            set
            {
                m_Color = value;
            }
        }

        public float U
        {
            get { return m_UV.X; }
            set { m_UV.X = value; }
        }


        public float V
        {
            get { return m_UV.Y; }
            set { m_UV.Y = value; }
        }
    };

    public class UWB_XNAGraphicsSystem
    {
        private EffectPool m_EffectPool;
        private BasicEffect m_BasicEffect;
        private GraphicsDevice m_XNA_GraphicsDevice;
        private ContentManager mResources;
        public static UWB_XNAGraphicsSystem m_TheAPI = new UWB_XNAGraphicsSystem();
        private RGameView mService;

        public BasicEffect MyEffect
        {
            get
            {
                return m_BasicEffect;
            }
            set
            {
                m_BasicEffect = value;
            }
        }

        private UWB_XNAGraphicsSystem()
        {
        }

        public bool CreateGraphicsContext(IntPtr hwnd, ref PresentationParameters pp)
        {
            //define presentation parameters
            pp = new PresentationParameters();
            pp.BackBufferCount = 1;
            pp.BackBufferFormat = SurfaceFormat.Unknown;
            pp.DeviceWindowHandle = hwnd;
            pp.IsFullScreen = false;
            pp.SwapEffect = SwapEffect.Discard;
            pp.BackBufferHeight = Control.FromHandle(hwnd).Height;
            pp.BackBufferWidth = Control.FromHandle(hwnd).Width;

            if (m_XNA_GraphicsDevice != null)
                return false;
            //create an XNA graphics device
            m_XNA_GraphicsDevice = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, DeviceType.Hardware,
                hwnd, pp);

            //check if graphics device was created
            Debug.Assert(m_XNA_GraphicsDevice != null, "XNA Graphics Device did not Initialize");

            m_XNA_GraphicsDevice.Reset(pp);
            m_XNA_GraphicsDevice.VertexDeclaration = new VertexDeclaration(m_XNA_GraphicsDevice, DeviceVertexFormat.VertexElements);
            m_XNA_GraphicsDevice.RenderState.CullMode = CullMode.None;
            m_XNA_GraphicsDevice.RenderState.FillMode = FillMode.Solid;


            m_EffectPool = new EffectPool();
            m_BasicEffect = new BasicEffect(m_XNA_GraphicsDevice, m_EffectPool);

            //set the model matrix to identity
            m_BasicEffect.World = Matrix.Identity;
            m_BasicEffect.View = Matrix.Identity;
            m_BasicEffect.Projection = Matrix.Identity;

            RGraphicsDeviceService gS = new RGraphicsDeviceService();
            gS.GraphicsDevice = m_XNA_GraphicsDevice;
            mService = new RGameView();
            mService.SetService(gS);
            mResources = new ContentManager(mService);
            mResources.RootDirectory = ".";

            return true;
        }

        public GraphicsDevice GetActiveDevice()
        {
            return m_XNA_GraphicsDevice;
        }

        public bool BeginScene(PresentationParameters pp)
        {
            if (m_XNA_GraphicsDevice == null)
                return false;
            m_XNA_GraphicsDevice.Reset(pp);
            m_XNA_GraphicsDevice.VertexDeclaration = new VertexDeclaration(m_XNA_GraphicsDevice, DeviceVertexFormat.VertexElements);
            m_XNA_GraphicsDevice.RenderState.CullMode = CullMode.None;
            m_XNA_GraphicsDevice.RenderState.FillMode = FillMode.Solid;
            m_XNA_GraphicsDevice.Clear(new Color(new Vector4(.8f, .8f, .8f, 0)));

            m_BasicEffect.VertexColorEnabled = true;

            m_BasicEffect.Begin();
            m_BasicEffect.CurrentTechnique.Passes[0].Begin();

            return true;
        }

        public bool EndSceneAndShow(PresentationParameters pp)
        {
            if (m_XNA_GraphicsDevice == null)
                return false;

            m_BasicEffect.CurrentTechnique.Passes[0].End();
            m_BasicEffect.End();
            m_XNA_GraphicsDevice.Present();

            return true;
        }

        public void setViewMatrix(Matrix matrix)
        {
            m_BasicEffect.View = matrix;
            m_BasicEffect.CommitChanges();
        }

        public void setWorldMatrix(Matrix matrix)
        {
            m_BasicEffect.World = matrix;
            m_BasicEffect.CommitChanges();
        }

        public bool ActivateTexture(string texName)
        {
            Texture2D t = null;
            bool loaded = false;


            try
            {
                // check Textures folder, current folder, and what else?
                t = mResources.Load<Texture2D>("Content\\Textures\\" + texName);
                m_BasicEffect.Texture = t;
                m_BasicEffect.TextureEnabled = true;
                m_BasicEffect.VertexColorEnabled = false;
            }
            catch (Exception e)
            {
                //texture load failed - disable texturing
                m_BasicEffect.Texture = null;
                m_BasicEffect.TextureEnabled = false;
                m_BasicEffect.VertexColorEnabled = true;
                UWB_Utility.echoToStatusArea((e.Message));
            }
            m_BasicEffect.CommitChanges();
            
            return true;
        }

        public void DeactivateTexture()
        {
            m_BasicEffect.TextureEnabled = false;
            m_BasicEffect.Texture = null;
            m_BasicEffect.VertexColorEnabled = true;
            m_BasicEffect.CommitChanges();
        }
    }
}